#include "stdafx.h"
#include "GLRidgeWidget.h"
#include <iostream>
#include <sstream>
#include <string>
#include "DataPoint.h"
#include "Mesh.h"
#include <QFileDialog>
#include "Side.h"
#include <math.h>

#include <GL/glut.h>

// Camera movement parameters
const float CAMERA_ROT_X_0 = 0.0f;
const float CAMERA_ROT_Y_0 = 0.0f;
const float CAMERA_ROT_STEP = 0.1f;
const float CAMERA_TR_X_0 = 0.0f;
const float CAMERA_TR_Y_0 = 0.0f;
const float CAMERA_TR_Z_0 = -0.5f;
const float CAMERA_TR_STEP = 0.001f;
const float CAMERA_ZOOM_0 = 1.0f;
const float CAMERA_ZOOM_STEP = 0.0005f;


// ----------------------------------------

GLRidgeWidget::GLRidgeWidget(QWidget *parent): QGLWidget(parent) {
	this->setFocusPolicy(Qt::StrongFocus);
	this->setMouseTracking(true);

    // Camera movements
    this->tracking1 = false;
	this->tracking2 = false;
    this->cameraRotX = CAMERA_ROT_X_0;
    this->cameraRotY = CAMERA_ROT_Y_0;
    this->cameraTrX = CAMERA_TR_X_0;
    this->cameraTrY = CAMERA_TR_Y_0;
    this->cameraZoom = CAMERA_ZOOM_0;
	
	this->flow_data = new ImportData(); 
	this->alpha = -0.002;
	this->showRidgePoints = false;
	this->showRidgeLines = false;
	this->whiteBackdrop = true;
	this->showVolume = false;
	this->drawbackplate = false;
	this->gridnet = false;
	this->show_2d = true;
	this->slice = 2;
	this->pointsize = 4;
	this->linesize = 2;
	this->filepath = "testsets/Test05_TS43_r.csv";
	
    cout << "GLRidgeWidget Initialized" << endl;
	this->flow_data->initialize(this->filepath);
	this->flow_data->createDataVolume(20,30,40);
	this->detector = new RidgeDetector(this->flow_data);
	////2D
	//if(show_2d){
	this->generateMesh2d(this->slice);
	//}
	////3D
	//else{
	//	this->generateMesh3d();
	//}
}

GLRidgeWidget::GLRidgeWidget(){
}

GLRidgeWidget::~GLRidgeWidget(void){
}

void GLRidgeWidget::loadData(){
		QString fileName = QFileDialog::getOpenFileName(this, tr("Load Datafile"),
													 "",
													 tr("Files (*.csv)"));
		this->filepath = fileName.toStdString();
		
		delete flow_data;
		flow_data = new ImportData(); 

		this->flow_data->initialize(this->filepath);
		this->flow_data->createDataVolume(20,30,40);
		//2D
		//this->generateMesh2d(this->slice);
		//3D
		//this->generateMesh3d();
}

void GLRidgeWidget::updateAlpha(int a){
	this->alpha = -(double)a*0.0001;
	//2D
	if(show_2d){
		this->generateMesh2d(this->slice);
	}
	//3D
	/*else{
		this->generateMesh3d();
	}*/
}

void GLRidgeWidget::updateSlice(int s){
	this->toggleRidgePoints(false);
	this->toggleRidgeLines(false);
	this->toggleVolume(true);
	this->slice = s;
	//2D
	if(show_2d){
		this->generateMesh2d(this->slice);
	}
	//3D
	//else{
	//	this->generateMesh3d();
	//}
}

void GLRidgeWidget::toggleGrid(bool checked){
	if(checked){
		this->drawBoundingBox();
		drawbackplate = true;
	}
	else{
		drawbackplate = false;
	}
	updateGL();
}

void GLRidgeWidget::toggleNet(bool checked){
	if(checked){
		gridnet = true;
	}
	else{
		gridnet = false;
	}
	updateGL();
}

void GLRidgeWidget::exportToObject(){
	this->m.toWaveFrontObject();
}

void GLRidgeWidget::toggleDimension(bool checked){
	if(checked){
		//2D
		this->generateMesh2d(this->slice);
		show_2d = true;
	}
	else{
		//3D
		this->generateMesh3d();
		show_2d = false;
	}
	updateGL();
}
void GLRidgeWidget::toggleMostconvex(bool checked){
	this->detector->setMostConvex(checked);
	//this->drawRidgeLines();
	this->updateGL();
}

void GLRidgeWidget::updatePointsize(QString s){
	this->pointsize = s.toDouble();
	this->updateGL();
}

void GLRidgeWidget::updateLinesize(QString s){
	this->linesize = s.toDouble();
	this->updateGL();
}

void GLRidgeWidget::toggleRidgePoints(bool checked){
	if(checked){
		this->drawRidgePoints3d();
		showRidgePoints = true;
	}
	else{
		showRidgePoints = false;
	}
	updateGL();
}

void GLRidgeWidget::toggleRidgeLines(bool checked){
	if(checked){
		//this->drawRidgeLines();
		//this->drawSurface();
		showRidgeLines = true;
	}
	else{
		showRidgeLines = false;
	}
	updateGL();
}

void GLRidgeWidget::toggleVolume(bool checked){
	if(checked){
		showVolume = true;
	}
	else{
		showVolume = false;
	}
	updateGL();
}

void GLRidgeWidget::toggleBackdrop(bool checked){
	if(checked){
		whiteBackdrop = true;
	}
	else{
		whiteBackdrop = false;
	}
	updateGL();
}

void GLRidgeWidget::generateMesh2d(int slice){ //Actually YZ
	//cout << "Generating mesh.. " << endl;
	//double fmin = -38;
	//double fmax = 115;
	/*double fmin = -150;
	double fmax = 150;*/
	//double val; 
	double inten;
	int i, j; // used to loop along the 2 direction of the slice
	vec3d v1, v2, v3, v4; // vertices of a couple of triangles of the mesh
	vec3d i1, i2, i3, i4; // vertices for the intensity of a couple of triangles of the mesh
	vec3d bound = this->flow_data->getAxes();
	int SLICE_WIDTH = bound.z()-1;
	int SLICE_HEIGHT = bound.y()-1;

	double tricount = (SLICE_WIDTH*SLICE_HEIGHT)*2;
	double vertcount = (tricount*3);
	emit setProgressFinish((int)tricount); //set the finish point for the progress bar
	//std::cout << "NUMBER OF TRIANGLES: " << tricount << std::endl;
	//std::cout << "NUMBER OF VERTICES: " << vertcount << std::endl;
	//delete m;
	
	m = Mesh(vertcount,tricount,tricount,1);
	m.setFaceCount(0,tricount);
	
	//Detect Ridgepoints
	this->detector->extractRidges(this->slice); //2D
	//this->detector->extractRidges3d(); //3D
	int count = 0;
	for(i = 0; i < SLICE_WIDTH; ++i) {
		for(j = 0; j < SLICE_HEIGHT; ++j) {
			//Retreive 4 vectors from the dataset
			v1 = this->flow_data->getPoint(i,j,slice);
			v2 = this->flow_data->getPoint(i,j+1,slice);
			v3 = this->flow_data->getPoint(i+1,j,slice);
			v4 = this->flow_data->getPoint(i+1,j+1,slice);
			
			//Assign heightvalue to given vectors from FTLE and alpha values
			v1.z() = this->alpha * this->flow_data->getVolume()[slice][j][i].getFTLE();
			v2.z() = this->alpha * this->flow_data->getVolume()[slice][j+1][i].getFTLE();
			v3.z() = this->alpha * this->flow_data->getVolume()[slice][j][i+1].getFTLE();
			v4.z() = this->alpha * this->flow_data->getVolume()[slice][j+1][i+1].getFTLE(); 

			//Assign heightvalue to given vectors from FTLE and alpha values using sigmoid function
			/*v1.z() = 1/ (1+ pow(M_E,(-alpha * data->getVolume()[i][j][slice].getFTLE())));
			v2.z() = 1/ (1+ pow(M_E,(-alpha * data->getVolume()[i][j+1][slice].getFTLE())));
			v3.z() = 1/ (1+ pow(M_E,(-alpha * data->getVolume()[i+1][j][slice].getFTLE())));
			v4.z() = 1/ (1+ pow(M_E,(-alpha * data->getVolume()[i+1][j+1][slice].getFTLE()))); */

			//Find intensity values for each vertex
			//inten = (v1.z()/alpha + v2.z()/alpha + v3.z()/alpha)/3;
			////std::cout << "inten: " << inten << std::endl;
			inten = this->flow_data->getVolume()[slice][j][i].getSigma();
			//val = (inten -fmin) / (fmax-fmin);
			//cout << inten << " + " << fmax << " / " << (fmax-fmin) << endl; 
			//val = (inten+fmax)/(fmax-fmin);
			if(inten > 0){
				i1.x() = 1;
				i1.y() = 0;
				i1.z() = 0;
			}
			else if(inten < 0){
				i1.x() = 0;
				i1.y() = 0;
				i1.z() = 1;
			}
			else{
				i1.x() = 0;
				i1.y() = 1;
				i1.z() = 0;
			}
			/*i1.x() = 0;
			i1.y() = 0;
			i1.z() = 1-val;*/

			inten = this->flow_data->getVolume()[slice][j+1][i].getSigma();
			//val = (inten+fmax)/(fmax-fmin);
			if(inten > 0){
				i2.x() = 0;
				i2.y() = 0;
				i2.z() = 0;
			}
			else if(inten < 0){
				i2.x() = 0;
				i2.y() = 0;
				i2.z() = 0;
			}
			else{
				i2.x() = 0;
				i2.y() = 1;
				i2.z() = 0;
			}
			/*i2.x() = 0;
			i2.y() = 0;
			i2.z() = 1-val;*/

			inten = this->flow_data->getVolume()[slice][j][i+1].getSigma();
			//val = (inten+fmax)/(fmax-fmin);
			if(inten > 0){
				i3.x() = 1;
				i3.y() = 0;
				i3.z() = 0;
			}
			else if(inten < 0){
				i3.x() = 0;
				i3.y() = 0;
				i3.z() = 1;
			}
			else{
				i3.x() = 0;
				i3.y() = 1;
				i3.z() = 0;
			}
			/*i3.x() = 0;
			i3.y() = 0;
			i3.z() = 1-val;*/

			inten = this->flow_data->getVolume()[slice][j+1][i+1].getSigma();
			//val = (inten+fmax)/(fmax-fmin);
			if(inten > 0){
				i4.x() = 1;
				i4.y() = 0;
				i4.z() = 0;
			}
			else if(inten < 0){
				i4.x() = 0;
				i4.y() = 0;
				i4.z() = 1;
			}
			else{
				i4.x() = 0;
				i4.y() = 1;
				i4.z() = 0;
			}
			/*i4.x() = 0;
			i4.y() = 0;
			i4.z() = 1-val;*/

			//cout << "G1: " << this->flow_data->getVolume()[slice][j][i].getSigma() << endl;
			//cout << "G2: " << this->flow_data->getVolume()[slice][j+1][i].getSigma() << endl;
			//cout << "G3: " << this->flow_data->getVolume()[slice][j][i+1].getSigma() << endl;
			//cout << "G4: " << this->flow_data->getVolume()[slice][j+1][i+1].getSigma() << endl;
			//cout << endl;
			//Add triangles to mesh
			m.addTriangle(v1,v2,v3,0,i1,i2,i3);
			m.addTriangle(v3,v2,v4,0,i3,i2,i4);
			count +=2;
			emit updateProgress(count);
		}
	}
	this->updateGL();
	//cout << "Done..: " <<  endl;
	//cout << "Number Of Triangles Stored: " << tricount << endl;
	//cout << "Number Of Vertices Stored: " << m.getNumberOfVertices() << "/" << vertcount << endl;
}

void GLRidgeWidget::drawBoundingBox(){
	std::vector<VectorXd> front,back,left,right,top,bottom;
	front.resize(4);
	back.resize(4);
	left.resize(4);
	right.resize(4);
	top.resize(4);
	bottom.resize(4);
	int xmin,ymin,zmin;
	int xmax,ymax,zmax;
	xmax = this->flow_data->getWidth()-1;
	ymax = this->flow_data->getHeight()-1;
	zmax = this->flow_data->getDepth()-1;
	xmin = ymin = zmin = 0;

	//bottomleft = 0, bottomright = 1 
	//topleft = 2, topright = 3
	front[0] = this->flow_data->getPoint_Eigen(xmin,ymin,zmin);
	front[1] = this->flow_data->getPoint_Eigen(xmax,ymin,zmin);
	front[2] = this->flow_data->getPoint_Eigen(xmin,ymax,zmin);
	front[3] = this->flow_data->getPoint_Eigen(xmax,ymax,zmin);

	back[0] = this->flow_data->getPoint_Eigen(xmin,ymin,zmax);
	back[1] = this->flow_data->getPoint_Eigen(xmax,ymin,zmax);
	back[2] = this->flow_data->getPoint_Eigen(xmin,ymax,zmax);
	back[3] = this->flow_data->getPoint_Eigen(xmax,ymax,zmax);

	left[0] = this->flow_data->getPoint_Eigen(xmin,ymin,zmax);
	left[1] = this->flow_data->getPoint_Eigen(xmin,ymin,zmin);
	left[2] = this->flow_data->getPoint_Eigen(xmin,ymax,zmax);
	left[3] = this->flow_data->getPoint_Eigen(xmin,ymax,zmin);

	right[0] = this->flow_data->getPoint_Eigen(xmax,ymin,zmin);
	right[1] = this->flow_data->getPoint_Eigen(xmax,ymin,zmax);
	right[2] = this->flow_data->getPoint_Eigen(xmax,ymax,zmin);
	right[3] = this->flow_data->getPoint_Eigen(xmax,ymax,zmax);

	/*top[0] = this->flow_data->getPoint_Eigen(xmin,ymax,zmin);
	top[1] = this->flow_data->getPoint_Eigen(xmax,ymax,zmin);
	top[2] = this->flow_data->getPoint_Eigen(xmin,ymax,zmax);
	top[3] = this->flow_data->getPoint_Eigen(xmax,ymax,zmax);*/

	bottom[0] = this->flow_data->getPoint_Eigen(xmin,ymin,zmin);
	bottom[1] = this->flow_data->getPoint_Eigen(xmax,ymin,zmin);
	bottom[2] = this->flow_data->getPoint_Eigen(xmin,ymin,zmax);
	bottom[3] = this->flow_data->getPoint_Eigen(xmax,ymin,zmax);
	
	box.clear();
	box.push_back(front);
	box.push_back(back);
	box.push_back(left);
	box.push_back(right);
	//box.push_back(top);
	box.push_back(bottom);
}

void GLRidgeWidget::generateMesh3d(){
	this->detector->extractRidges3d(); //3D
	this->drawSurface();
	this->drawRidgeLines();
	this->updateGL();
}

void GLRidgeWidget::drawPoint(VectorXd& point,VectorXd c){
	//cout << "drawing point: \n" << point << endl;
	glColor3f(c.x(),c.y(),c.z());
	glPointSize(this->pointsize);
	glBegin(GL_POINTS);
		glVertex3f(point.x(),point.y(),point.z());
	glEnd();
}

void GLRidgeWidget::drawLine(VectorXd start,VectorXd end,VectorXd c){
	//cout << "drawing line" << start.transpose() << " to " << end.transpose() << " color: " << c.transpose() << endl;
	glColor3f(c.x(),c.y(),c.z());
	glLineWidth(this->linesize);
	glBegin(GL_LINES);
		glVertex3f(start.x(),start.y(),start.z());
		glVertex3f(end.x(),end.y(),end.z());
		
	glEnd();
}

void GLRidgeWidget::drawSlice(){
	//int i, j,k; // used to loop along the 2 direction of the slice
	//vec3d bound = this->flow_data->getAxes();
	//int SLICE_DEPTH = bound.z();
	//int SLICE_WIDTH = bound.y();
	////int SLICE_HEIGHT = bound.z();
	////int zp = 1;
	//double ftle;
	//vec3d point;
	//for(k = 0; k < SLICE_DEPTH; ++k) {
	//	for(i = 0; i < SLICE_WIDTH; ++i) {
	//		//for(j = 0; j < SLICE_HEIGHT; ++j) {

	//			point = this->flow_data->getPoint(k,i,this->slice);
	//			point.z() = this->flow_data->getVolume()[this->slice][i][k].getFTLE();
	//			//if(!data->getVolume()[zp][i][k].isEmpty()){
	//			if(ftle != 0){
	//				drawPoint(point);
	//			}
	//			
	//	}
	//}	

}

void GLRidgeWidget::initializeGL(){
	// OpenGL init
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_COLOR_MATERIAL);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHT1);
	glEnable(GL_NORMALIZE);
	glEnable(GL_POINT_SMOOTH);
	/*if(this->whiteBackdrop){
		glClearColor(1.0,1.0,1.0,0.0);
	}
	else{
		glClearColor(0.0,0.0,0.0,0.0);
	}*/


}

void GLRidgeWidget::resizeGL(int w, int h){
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
	gluPerspective(30,
			static_cast<float> (w) / static_cast<float> (h), 0.0001f,
			10.0f);
	glMatrixMode(GL_MODELVIEW);

}

void GLRidgeWidget::paintGL(){
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//SET UP LIGHTS
	GLfloat ambientColor[] = {0.2f,0.2f,0.2f,1.0f};
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambientColor);

	GLfloat lightColor0[] = {0.9f,0.9f,0.9f,1.0f};
	GLfloat lightPos0[] = {0.2, 0.5, -8, 1};
	glLightfv(GL_LIGHT0,GL_DIFFUSE,lightColor0);
	glLightfv(GL_LIGHT0,GL_POSITION,lightPos0);

	GLfloat lightColor1[] = {0.8f,0.8f,0.8f,1.0f};
	GLfloat lightPos1[] = {0.5, 0.2, 8, 1};
	glLightfv(GL_LIGHT1,GL_DIFFUSE,lightColor1);
	glLightfv(GL_LIGHT1,GL_POSITION,lightPos1);

	if(!this->whiteBackdrop){
		glClearColor(0.0,0.0,0.0,0.0);
	}
	else{
		glClearColor(1.0,1.0,1.0,0.0);
	}

	
    // Camera movements
    glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
    glTranslatef(cameraTrX, cameraTrY, CAMERA_TR_Z_0);
    glScalef(cameraZoom, cameraZoom, cameraZoom);
    glRotatef(-this->cameraRotY, 1.0f, 0.0f, 0.0f);
    glRotatef(+this->cameraRotX, 0.0f, 1.0f, 0.0f);

    // Centers the volume
    int xmax = this->flow_data->getWidth()-1;
	int ymax = this->flow_data->getHeight()-1;
	int zmax = this->flow_data->getDepth()-1;
    const VectorXd &minPoint = this->flow_data->getPoint_Eigen(0, 0, 0);
	const VectorXd &maxPoint = this->flow_data->getPoint_Eigen(xmax,ymax,zmax);
    glTranslatef(-(maxPoint.x() + minPoint.x()) / 2.0f, 
        -(maxPoint.y() + minPoint.y()) / 2.0f, 
        -(maxPoint.z() + minPoint.z()) / 2.0f);

    // --- This piece of code draws the "axis" as cubes, can be useful for debugging
    /*glColor3f(0,0,0);
    glutWireCube(0.03);
    glPushMatrix();
    glColor3f(1,0,0);
    glTranslatef(0.05, 0, 0);
    glutWireCube(0.03);
    glPopMatrix();
    glPushMatrix();
    glColor3f(0,1,0);
    glTranslatef(0, 0.05, 0);
    glutWireCube(0.03);
    glPopMatrix();
    glPushMatrix();
    glColor3f(0,0,1);
    glTranslatef(0, 0, 0.05);
    glutWireCube(0.03);
    glPopMatrix();*/


    if(drawbackplate){
		std::vector<Vector3d> color;
		color.resize(6);
		color[0] = Vector3d(1,0,0);
		color[1] = Vector3d(0,0,1);
		color[2] = Vector3d(0,1,0);
		color[3] = Vector3d(1,1,0);
		color[4] = Vector3d(0,1,1);
		color[5] = Vector3d(0.5,0.5,0.5);
		for(int i = 0;i< box.size();++i){
			for(int j = 0;j< box[i].size();j++){
				this->drawPoint(box[i][j],color[i]);
			}
			this->drawLine(box[i][0],box[i][1],color[i]);
			this->drawLine(box[i][0],box[i][2],color[i]);
			this->drawLine(box[i][1],box[i][3],color[i]);
			this->drawLine(box[i][2],box[i][3],color[i]);

		}
	}
	if(gridnet){
		Vector3d v1,v2,v3,v4,color;
		color << 0.5,0.5,0.5;
		int k;
		for(k = 1;k < this->flow_data->getDepth();++k){
			v1.x() = box[0][0].x();
			v1.y() = box[0][0].y();
			v1.z() = box[0][0].z() + (0.005 * k);
			v2.x() = box[0][1].x();
			v2.y() = box[0][1].y();
			v2.z() = box[0][1].z() + (0.005 * k);
			v3.x() = box[0][2].x();
			v3.y() = box[0][2].y();
			v3.z() = box[0][2].z() + (0.005 * k);
			v4.x() = box[0][3].x();
			v4.y() = box[0][3].y();
			v4.z() = box[0][3].z() + (0.005 * k);
			this->drawLine(v1,v2,color);
			this->drawLine(v1,v3,color);
			this->drawLine(v2,v4,color);
			this->drawLine(v3,v4,color);

		}
		for(k = 1;k < this->flow_data->getWidth();++k){
			v1.x() = box[2][0].x() + (0.005 * k);
			v1.y() = box[2][0].y();
			v1.z() = box[2][0].z();
			v2.x() = box[2][1].x() + (0.005 * k);
			v2.y() = box[2][1].y();
			v2.z() = box[2][1].z();
			v3.x() = box[2][2].x() + (0.005 * k);
			v3.y() = box[2][2].y();
			v3.z() = box[2][2].z();
			v4.x() = box[2][3].x() + (0.005 * k);
			v4.y() = box[2][3].y();
			v4.z() = box[2][3].z();
			this->drawLine(v1,v2,color);
			this->drawLine(v1,v3,color);
			this->drawLine(v2,v4,color);
			this->drawLine(v3,v4,color);

		}
		for(k = 1;k < this->flow_data->getHeight();++k){
			v1.x() = box[4][0].x();
			v1.y() = box[4][0].y() + (0.005 * k);
			v1.z() = box[4][0].z();
			v2.x() = box[4][1].x();
			v2.y() = box[4][1].y() + (0.005 * k);
			v2.z() = box[4][1].z();
			v3.x() = box[4][2].x();
			v3.y() = box[4][2].y() + (0.005 * k);
			v3.z() = box[4][2].z();
			v4.x() = box[4][3].x();
			v4.y() = box[4][3].y() + (0.005 * k);
			v4.z() = box[4][3].z();
			this->drawLine(v1,v2,color);
			this->drawLine(v1,v3,color);
			this->drawLine(v2,v4,color);
			this->drawLine(v3,v4,color);

		}
	}
	if(showRidgePoints){
		VectorXd p;
		p.resize(3);
		for(int i = 0;i<this->points.size();++i){
			p.x() =  this->points[i].x();
			p.y() =  this->points[i].y();
			if(show_2d){
				p.z() =  this->points[i].z() * this->alpha;
			}
			else{
				p.z() = this->points[i].z();
			}
			this->drawPoint(p);
		}
	}
	if(showRidgeLines){
		VectorXd s,e;
		s.resize(3);
		e.resize(3);
		//cout << "lstart size: " << lstart.size() << endl;
		//cout << "lend size: " << lend.size() << endl;
		for(int i = 0;i<this->lstart.size();++i){
			//cout << "i: " << i << endl;
			s.x() =  this->lstart[i].x();
			s.y() =  this->lstart[i].y();
			s.z() =  this->lstart[i].z() * this->alpha;
			
			e.x() =  this->lend[i].x();
			e.y() =  this->lend[i].y();
			e.z() =  this->lend[i].z() * this->alpha;
			this->drawLine(s,e,this->line_color[i]);
		}
		//this->drawRidgeLines();
	}
	if(showVolume){
		//cout << "Drawing Mesh!" << endl;
		this->m.drawTriangles(this->alpha);
	}
}

//Test to draw ridgepoints found between vertexes
void GLRidgeWidget::drawRidgePoints(){
	Edge element;
	queue<GridElement<Edge>> grid_lines;
	grid_lines = this->detector->getRidgePoints2d();
	VectorXd v;
	v.resize(3);
	this->points.clear();
	while(!grid_lines.empty()){
		for(int i = 0;i < grid_lines.front().getSize();++i){
			element = grid_lines.front().getElement(i);
			if(element.hasRidgePoint()){
				if(this->show_2d){
					v.x() = this->flow_data->getPoint(element.getRidgePoint().x(),element.getRidgePoint().y(),this->slice).x();
					v.y() = this->flow_data->getPoint(element.getRidgePoint().x(),element.getRidgePoint().y(),this->slice).y();
					v.z() = element.getRidgePoint_FTLE();
				}
				else{
					v = this->flow_data->getPoint_Eigen(element.getRidgePoint().x(),element.getRidgePoint().y(),element.getRidgePoint().z());
				}
				this->points.push_back(v);
			}
		}
		grid_lines.pop();
	}
}

void GLRidgeWidget::drawRidgePoints3d(){
	Side element;
	queue<GridElement<Side>> grid_lines;
	grid_lines = this->detector->getRidgePoints3d();
	std::vector<Edge> edges; //4 edges per plane
	edges.resize(4);
	int count = 0;
	VectorXd v,color;
	v.resize(3);
	color.resize(3);
	this->points.clear();
	this->point_color.clear();
	this->setProgressFinish(grid_lines.size());
	while(!grid_lines.empty()){
		for(int i = 0;i < 6;++i){
			element = grid_lines.front().getElement(i);
			edges = element.getEdges();
			for(int j = 0;j < edges.size();++j){
				if(edges[j].hasRidgePoint()){
					v = this->flow_data->getPoint_Eigen(edges[j].getRidgePoint().x(),edges[j].getRidgePoint().y(),edges[j].getRidgePoint().z());
					color = grid_lines.front().getColor();
					this->points.push_back(v);
					this->point_color.push_back(color);
				}//if 
			}//for j
		}//for i
		count += 1;
		emit updateProgress(count);
		grid_lines.pop();
	}//while !empty
}

//2D
void GLRidgeWidget::drawRidgeLines(){
	Edge line_start,line_end;
	queue<GridElement<Side>> grid_lines;
	grid_lines = this->detector->getFaceLines();
	this->lstart.resize(this->detector->getVertCount());
	this->lend.resize(this->detector->getVertCount());
	this->line_color.resize(this->detector->getVertCount());
	cout << "Line elements: " << this->detector->getVertCount() << endl;
	std::vector<VectorXi> line_element;
	std::vector<Edge> s_edges;
	s_edges.resize(4);
	VectorXd v1,v2,color;
	v1.resize(3);
	v2.resize(3);
	color.resize(3);
	//this->lstart.clear();
	//this->lend.clear();
	//this->line_color.clear();
	int c = 0;
	while(!grid_lines.empty()){
		for(int i = 0;i < 6;++i){
			line_element = grid_lines.front().getElement(i).getLines();
			s_edges = grid_lines.front().getElement(i).getEdges();
			//cout << "line_element: " << line_element.size() << endl;
			//cout << "edges: " << s_edges.size() << endl;
			if(line_element.size() > 0){
				for(int j = 0;j<line_element.size();++j){
					//cout << "start edge: " << line_element[j].x() << endl;
					//cout << "end edge: " << line_element[j].y() << endl;
					line_start = s_edges[line_element[j].x()];
					line_end = s_edges[line_element[j].y()];
					/*cout << "start edge: " << line_start.getRidgePoint() << endl;
					cout << "end edge: " << line_end.getRidgePoint() << endl;*/
					
					//if(show_2d){
					///*	v1.x() = this->flow_data->getPoint(line_start.getRidgePoint().x(),line_start.getRidgePoint().y(),this->slice).x();
					//	v1.y() = this->flow_data->getPoint(line_start.getRidgePoint().x(),line_start.getRidgePoint().y(),this->slice).y();
					//	v1.z() = line_start.getRidgePoint_FTLE();

					//	v2.x() = this->flow_data->getPoint(line_end.getRidgePoint().x(),line_end.getRidgePoint().y(),this->slice).x();
					//	v2.y() = this->flow_data->getPoint(line_end.getRidgePoint().x(),line_end.getRidgePoint().y(),this->slice).y();
					//	v2.z() = line_end.getRidgePoint_FTLE();
					//	color = grid_lines.front().getColor();*/
					//}
					//else{
					v1 = this->flow_data->getPoint_Eigen(line_start.getRidgePoint().x(),line_start.getRidgePoint().y(),line_start.getRidgePoint().z());
					v1.z() = line_start.getRidgePoint_FTLE();
					v2 = this->flow_data->getPoint_Eigen(line_end.getRidgePoint().x(),line_end.getRidgePoint().y(),line_end.getRidgePoint().z());
					v2.z() = line_end.getRidgePoint_FTLE();
					
					color = Vector3d(1,0,0); 
					//}
					//cout << "adding v1: " << v1.transpose() << " and v2: " << v2.transpose() << endl;
					this->lstart[c] = v1;
					this->lend[c] = v2;
					this->line_color[c] = color;
					c++;
					//cout << "count: " << c << endl;
				}//for
			}//if lines >0
		}//for
		grid_lines.pop();
	}
	cout << " Lines: " << c << endl;
}
//3d
void GLRidgeWidget::drawSurface(){
	cout << "Drawing surface" << endl;
	Edge line_start,line_end;
	queue<GridElement<Side>> grid_lines;
	grid_lines = this->detector->getRidgeLines3d();
	int triCount = this->detector->getTriCount();
	int vertCount = triCount*3;
	//cout << "number of vertices: " << vertCount << endl;
	//cout << "number of triangles: " << triCount << endl;
	m = Mesh(vertCount,triCount,triCount,1);
	m.setFaceCount(0,triCount);
	emit setProgressFinish(triCount);
	int c = 0;
	std::vector<std::vector<VectorXd>> triangles;
	VectorXd intensity;
	while(!grid_lines.empty()){
		triangles = grid_lines.front().getTriangles();
		for(int i = 0;i<triangles.size();i++){
			//cout << "adding triangle to mesh: " << triangles[i][0].transpose() << "," << triangles[i][1].transpose() << "," << triangles[i][2].transpose() << endl;
			//Add triangle to mesh
			intensity = grid_lines.front().getColor();
			m.addEigenTriangle(this->flow_data->getPoint_Eigen(triangles[i][0].x(),triangles[i][0].y(),triangles[i][0].z()),
							   this->flow_data->getPoint_Eigen(triangles[i][1].x(),triangles[i][1].y(),triangles[i][1].z()),
							   this->flow_data->getPoint_Eigen(triangles[i][2].x(),triangles[i][2].y(),triangles[i][2].z()),
							   0,intensity);
			c++;
		}
		emit updateProgress(c);
		grid_lines.pop();
	}
	cout << " Number of triangles: " << c << endl;
}

void GLRidgeWidget::keyPressEvent(QKeyEvent* ev){
	if(ev->key() == Qt::Key_Left){
		cameraTrX -= CAMERA_TR_STEP;
	}
	if(ev->key() == Qt::Key_Right){
		cameraTrX += CAMERA_TR_STEP;
	}
	if(ev->key() == Qt::Key_R){
		//this->showRidges = true;
		//this->updateGL();
	}
	if(ev->key() == Qt::Key_Up){
		cameraTrY += CAMERA_TR_STEP;
	}
	if(ev->key() == Qt::Key_Down){
		cameraTrY -= CAMERA_TR_STEP;
	}
	if(ev->key() == Qt::Key_Space){
		cameraRotX = CAMERA_ROT_X_0;
        cameraRotY = CAMERA_ROT_Y_0;
        cameraTrX = CAMERA_TR_X_0;
        cameraTrY = CAMERA_TR_Y_0;
        cameraZoom = CAMERA_ZOOM_0;
	}
    this->updateGL();
}

void GLRidgeWidget::wheelEvent(QWheelEvent* ev){
        this->cameraZoom += ev->delta() * CAMERA_ZOOM_STEP;
        if(this->cameraZoom <= 0)
            this->cameraZoom = CAMERA_ZOOM_STEP;
		this->updateGL();
}

void GLRidgeWidget::mousePressEvent(QMouseEvent* ev){
	if(ev->button() == 1){
        this->prevMousePos = ev->pos();    
        this->tracking1 = true;
	} else if(ev->button() == 2){
        this->prevMousePos = ev->pos();
		this->tracking2 = true;
	}
}

void GLRidgeWidget::mouseMoveEvent(QMouseEvent* ev){
    if(this->tracking1){
        // If button one is pressed, update the rotation amounts
        float diffX = ev->pos().x() - this->prevMousePos.x();
        float diffY = this->prevMousePos.y() - ev->pos().y();
        cameraRotX += diffX * CAMERA_ROT_STEP;
        cameraRotY += diffY * CAMERA_ROT_STEP;
        this->prevMousePos = ev->pos();
        this->updateGL();
    } else if(this->tracking2){
        // If button two is pressed, update the translation amounts
        float diffX = ev->pos().x() - this->prevMousePos.x();
        float diffY = this->prevMousePos.y() - ev->pos().y();
        cameraTrX += diffX * CAMERA_TR_STEP;
        cameraTrY += diffY * CAMERA_TR_STEP;
        this->prevMousePos = ev->pos();
        this->updateGL();
    }
}

void GLRidgeWidget::mouseReleaseEvent(QMouseEvent* ev){
	if(ev->button() == 1){
		this->tracking1 = false;
	}
	if(ev->button() == 2){
		this->tracking2 = false;
	}
}
